home *** CD-ROM | disk | FTP | other *** search
/ Technotools / Technotools (Chestnut CD-ROM)(1993).ISO / batch / bat / batstk.asm < prev    next >
Assembly Source File  |  1985-10-16  |  17KB  |  358 lines

  1.          PAGE  60,132
  2.          TITLE BATSTACK -- Special device driver for EBL keyboard stack
  3.          COMMENT $
  4.  
  5.          BATSTACK                 Nathaniel R. Goodspeed
  6.  
  7. --------
  8. Overview
  9. --------
  10. This device driver supports the "keyboard stack" available through use of the
  11. Extended Batch Language, EBL.  Normally, the only way to get stuff into the
  12. keyboard stack is to use the EBL commands STACK or BEGSTACK ... END.  (Programs
  13. remove entries from the stack by attempting normal keyboard reads, and EBL
  14. provides a way to read the stack into EBL variables.)  But BATSTACK allows the
  15. output of any program to be produced into the stack, using normal DOS output
  16. redirection:
  17.  
  18. echo This is going into the keyboard stack>batstack
  19.  
  20. Obviously, the use of STACK or BEGSTACK is better than ECHOing into BATSTACK.
  21. But the power of BATSTACK is that any filter can produce output into the 
  22. keyboard stack, for use by any other program, or for further processing by
  23. EBL programs.  
  24.  
  25. ------------
  26. Installation
  27. ------------
  28. BATSTACK is created by assembling BATSTK.ASM, linking it, and converting it
  29. to a .COM-form file with the extension .DEV (so nobody tries to execute it
  30. by typing its name, which would result in chaos).
  31.          masm batstk,batstk,batstk,nul;
  32.          link batstk;
  33.          exe2bin batstk.exe batstk.dev
  34.          del batstk.obj
  35.          del batstk.exe
  36.  
  37. Once you have BATSTK.DEV, it is installed by adding a line to your CONFIG.SYS 
  38. file of the form:
  39.          DEVICE=BATSTK.DEV
  40. You must either ensure that BATSTK.DEV is in the root directory of your boot
  41. disk, or supply the full drive and pathname of its location, e.g.:
  42.          DEVICE=C:\DEVICES\BATSTK.DEV
  43. BATSTACK will be installed when the system is next rebooted.  It will announce
  44. its presence with the message "BATSTACK driver loaded."
  45.  
  46. You may be wondering why, since the device is called BATSTACK, the files used
  47. to implement it are called BATSTK.* .  The reason is that once a device with
  48. a particular name is installed in your system, DOS ignores any extension given
  49. with that device name!  In other words, if the BATSTACK source and device files
  50. were named BATSTACK.ASM and BATSTACK.DEV, DOS would forget that the disk files
  51. were there as soon as the BATSTACK device was installed.  The command line
  52. "type batstack.asm" would be treated the same as "type batstack", and would 
  53. cause the contents of the stack to be typed!  (This is why it's not possible
  54. to create a disk file called CON.TXT, too.)
  55.  
  56. -----------
  57. Usage Notes
  58. -----------
  59. There are two cases in which you might want to redirect a filter's output to
  60. BATSTACK rather than a file or pipe.  The first to let an EBL batch file
  61. read the output, so that (for instance) a batch file can know a file's size
  62. without having to display DIR output on the screen and find it using READSCRN.
  63.  
  64. The second case is when you want the filter to supply some, but not all, of
  65. the input for a program to follow.  When a program thinks it's reading the
  66. keyboard, it will read the stack until it is exhausted, then revert to reading 
  67. the real keyboard.  So to supply the first few commands for program2 from 
  68. program1, you could place in a batch file the lines:
  69.          program1 >batstack
  70.          program2
  71. By contrast, if you connect the two programs with a DOS pipeline:
  72.          program1 | program2
  73. or redirect the output of the first into a file, and read that with the second:
  74.          program1 >miscfile
  75.          program2 <miscfile
  76. then program1 had better generate an explicit command to cause program2 to 
  77. terminate, or else program2 might reach end-of-file on the pipeline or file and
  78. wait indefinitely for a termination command to appear, without allowing it to
  79. be typed from the real keyboard!  If program2 is itself a filter, or at any
  80. rate was coded to recognize end-of-file on standard input, it will terminate at
  81. end-of-file.  But in no case will it automatically switch to the real keyboard.
  82.  
  83. Don't try to copy a large amount of text into BATSTACK, however.  The EBL 2.04a
  84. stack handler apparently isn't very careful about checking for stack-full, at
  85. least not when text is entered with the INT 16H, AH=73H option.  Not only is
  86. there no defined way to detect a stack-full condition on return from the INT,
  87. but when I attempted to copy a 537-byte file into a stack initialized with the
  88. usual BAT * 512 command, the ctrl-PrtSc key stopped working!  (DOS echoed ^P
  89. at the command prompt rather than echoing following characters to the printer.)
  90.  
  91. --------------------
  92. Implementation Notes
  93. --------------------
  94. The Extended Batch Language STACK and BEGSTACK commands normally delimit each
  95. line in the stack with a CR, rather than a CR/LF as DOS text lines normally end.
  96. This is consistent with the pretext that the stack contains user keystrokes;
  97. the user never types an explicit LF.  However, since the BATSTACK driver is
  98. expected to handle normal DOS text files, it performs a transformation:  when
  99. CR/LF is written to BATSTACK, the LF is discarded; when CR is read from BATSTACK,
  100. an LF is automatically appended.  In theory, unless the text written to BATSTACK
  101. already contains CR characters without LFs, this should be transparent if the
  102. BATSTACK driver is both written and read by DOS:
  103.          copy myfile batstack
  104.          copy batstack myfile.new
  105. But when the stack is read via keyboard requests, no spurious LFs will show up.
  106.  
  107. Another funny convention followed by BATSTACK when being read as a DOS device
  108. is that there is always a character ready to be read -- but if the stack is 
  109. empty or disabled, the character returned by BATSTACK will be a simulated 
  110. ctrl-Z, to cause DOS programs to recognize end-of-file.  The DOS device driver 
  111. documentation suggests that if a driver sets the "busy" bit meaning that no 
  112. character is currently available, DOS will wait under some circumstances until 
  113. the "busy" bit is reset.  We can be almost positive, however, that if the stack 
  114. is empty or disabled, no new characters will appear in it no matter how long 
  115. DOS might wait.  This is why we always claim that we have a character ready.
  116.  
  117. A useful enhancement to the EBL INT 16H stack support would be a status return 
  118. on functions 73H and 74H, so programs could tell if the write failed.  Another
  119. would be a function to request the current stack enable/disable status and the
  120. length of the current contents.  This would let programs specifically interes-
  121. ted in the stack, not the keyboard, read it even if it were disabled, saving 
  122. and restoring the user's enable/disable state.
  123.  
  124. NRG 09/05/85
  125. $
  126.          PAGE
  127. MYSTACKSIZE EQU 256               ;DOS MANUAL CLAIMS DEVICE DRIVERS NEED OWN STACK
  128. LF       EQU   0AH                ;LINE-FEED CHARACTER
  129. CR       EQU   0DH                ;CARRIAGE-RETURN CHARACTER
  130. EOF      EQU   1AH                ;CTRL-Z IS END-OF-FILE MARKER
  131.  
  132. LJZ      MACRO DEST
  133.          LOCAL NZDEST
  134.          JNZ   NZDEST
  135.          JMP   DEST
  136. NZDEST:
  137.          ENDM
  138.  
  139. DEVATTR  RECORD DEVCHAR:1=0, DEVIOCTL:1=0, DEVNONIBM:1=0, UNUSED:9=0, DEVCLOCK:1=0, DEVNUL:1=0, DEVSTDOUT:1=0, DEVSTDIN:1=0
  140.  
  141. DUMMY    STRUC
  142. WORDSIZE DW    ?
  143. DUMMY    ENDS
  144.  
  145. ;        DEVICE HEADER
  146.  
  147. CSEG     SEGMENT BYTE PUBLIC 'CODE'
  148.          DD    -1                 ;REQUIRED; WILL BECOME PTR TO NEXT DRIVER
  149.          DEVATTR <1,0>            ;DEVICE ATTRIBUTES: CHAR, NO IOCTL SUPPORT
  150.          DW    OFFSET STRATEGY    ;PTR TO DEVICE STRATEGY ROUTINE
  151.          DW    OFFSET INTERRUPT   ;PTR TO DEVICE INTERRUPT ROUTINE
  152.          DB    'BATSTACK'         ;DEVICE NAME -- BETTER BE DIFFERENT FROM
  153.                                   ;OUR SOURCE, BINARY ETC. OR WE CAN'T ACCESS
  154.                                   ;DISK FILES ONCE IT'S INSTALLED!
  155.  
  156. REQHDR   DD    ?                  ;SAVE REQUEST HEADER PTR HERE
  157. MYSP     DW    -2                 ;FIRST CALL, SET SP ALMOST AS HIGH AS CAN REACH
  158.                                   ;(FOR INIT, WE HAVE ALL OF MEMORY TO OURSELVES)
  159. OLDSP    DW    ?                  ;SAVE DOS SP/SS HERE
  160. OLDSS    DW    ?
  161. LASTREAD DB    00H                ;LAST CHARACTER READ FROM STACK
  162. LASTWRITE DB   00H                ;LAST CHARACTER WRITTEN TO STACK
  163.  
  164. STRATEGY PROC  FAR                ;ENTER HERE FOR STRATEGY ROUTINE
  165.          ASSUME CS:CSEG           ;ONLY CS POINTS TO US
  166.          MOV   WORD PTR REQHDR,BX ;SAVE PTR TO REQUEST HEADER
  167.          MOV   WORD PTR REQHDR+2,ES
  168.          RET                      ;SAVED REQUEST HEADER PTR; RETURN
  169. STRATEGY ENDP
  170.          PAGE
  171. FUNCTAB  EQU   THIS WORD          ;TABLE OF FUNCTIONS, SUBSCRIPTED BY COMMAND CODE
  172.          DW    INIT               ; 0 -- INIT
  173.          DW    DONE               ; 1 -- MEDIA CHECK (NOP FOR CHARACTER DEV)
  174.          DW    DONE               ; 2 -- BUILD BPB (NOP FOR CHARACTER DEV)
  175.          DW    UNKNOWN            ; 3 -- IOCTL INPUT
  176.          DW    READ               ; 4 -- INPUT (READ)
  177.          DW    TESTREAD           ; 5 -- NON-DESTRUCTIVE INPUT NO WAIT
  178.          DW    INSTATUS           ; 6 -- INPUT STATUS
  179.          DW    INFLUSH            ; 7 -- INPUT FLUSH
  180.          DW    WRITE              ; 8 -- OUTPUT (WRITE)
  181.          DW    WRITE              ; 9 -- OUTPUT (WRITE) WITH VERIFY
  182.          DW    DONE               ;10 -- OUTPUT STATUS
  183.          DW    DONE               ;11 -- OUTPUT FLUSH (WE DON'T BUFFER OUTPUT)
  184.          DW    UNKNOWN            ;12 -- IOCTL OUTPUT
  185. FUNCCNT  EQU   ($-FUNCTAB)/(TYPE WORDSIZE)
  186.  
  187. INTERRUPT PROC FAR                ;HERE TO PERFORM THE REQUEST JUST 'ENQUEUED'
  188.          ASSUME CS:CSEG
  189.          PUSH  DS
  190.          PUSH  SI
  191.          PUSH  ES
  192.          PUSH  DI
  193.          PUSH  AX
  194.          PUSH  BX
  195.          PUSH  CX
  196.          MOV   AX,CS              ;PTR TO THIS SEGMENT
  197.          MOV   OLDSP,SP           ;SAVE OLD STACK
  198.          MOV   OLDSS,SS
  199.          MOV   SS,AX              ;SET NEW STACK
  200.          MOV   SP,MYSP
  201.          LDS   SI,REQHDR          ;GET FULL PTR TO REQUEST HEADER
  202.          MOV   BL,DS:[SI+2]       ;GET COMMAND CODE
  203.          CMP   BL,FUNCCNT         ;CHECK VALIDITY
  204.          JAE   UNKNOWN            ;NOT RECOGNIZED
  205.          XOR   BH,BH              ;BX = BL
  206.          SHL   BX,1               ;DOUBLE FOR WORD OFFSET INTO FUNCTAB
  207.          CLD                      ;SET DIRECTION TO 'FORWARD'
  208.          JMP   FUNCTAB[BX]        ;SWITCH TO APPROPRIATE ROUTINE
  209. UNKNOWN: 
  210.          OR    WORD PTR DS:[SI+3],8103H ;SET ERROR, DONE AND 'UNKNOWN COMMAND'
  211.          JMP   SHORT EXIT
  212. DONE:
  213.          OR    BYTE PTR DS:[SI+4],01  ;SET DONE BIT
  214. EXIT:
  215.          MOV   SS,OLDSS           ;RESTORE ORIGINAL STACK
  216.          MOV   SP,OLDSP
  217.          POP   CX
  218.          POP   BX
  219.          POP   AX
  220.          POP   DI
  221.          POP   ES
  222.          POP   SI
  223.          POP   DS
  224.          RET
  225. INTERRUPT ENDP
  226.          PAGE
  227. READ     PROC  NEAR               ; 4 -- INPUT (READ)
  228.          MOV   CX,DS:[SI+18]      ;PICK UP BYTE COUNT
  229.          JCXZ  DONE               ;IGNORE TRIVIAL REQUESTS
  230.          LES   DI,DS:[SI+14]      ;PICK UP TRANSFER ADDRESS
  231. READLOOP:
  232.          CMP   LASTREAD,CR        ;WAS THE LAST CHAR WE READ A CR?
  233.          JNE   REALREAD           ;IF NOT, READ ANOTHER CHAR
  234.          MOV   AL,LF              ;LAST CHAR WAS CR: SIMULATE FOLLOWING LF
  235.          JMP   SHORT READSTORE
  236. REALREAD:                         ;HERE WHEN NOT SIMULATING LF
  237.          MOV   AX,7600H           ;AH = 76H (CHAR SOURCE TO AL); AL = 00H
  238.          INT   16H                ;IF BAT NOT INSTALLED, AL NOT CHANGED
  239.                                   ;IF BAT INSTALLED, AL = 'K'EYBOARD/'S'TACK
  240.          TEST  AL,AL              ;CHECK FOR UNCHANGED AL
  241.          JZ    UNKNOWN            ;IF BAT NOT INSTALLED, WE DON'T SUPPORT FUNCTION
  242.          CMP   AL,'S'             ;DO WHILE STILL CHARS IN STACK
  243.          JNE   READDONE
  244.          XOR   AH,AH              ;AH = 0: READ NEXT CHAR
  245.          INT   16H                ;GET CHAR INTO AL
  246. READSTORE:                        ;HERE AL HAS CHAR TO RETURN
  247.          STOSB                    ;STORE INTO BUFFER, INCREMENT POINTER
  248.          MOV   LASTREAD,AL        ;SAVE TO CHECK FOR CR/LF SIMULATION
  249.          LOOP  READLOOP           ;LOOP UNTIL ALL REQUESTED BYTES READ
  250.          JMP   SHORT READX        ;AND WHEN THAT'S DONE, SKIP TO EXIT
  251. READDONE:                         ;HERE WHEN WE CAN'T SATISFY READ REQUEST
  252.          MOV   AL,EOF             ;GET EOF MARKER
  253.          STOSB                    ;SHOW IT TO CALLER
  254.          MOV   LASTREAD,AL        ;KEEP TRACK OF CHARS RETURNED TO CALLER
  255.          DEC   CX                 ;WE SATISFIED ONE MORE REQUESTED CHARACTER
  256. READX:
  257.          SUB   DS:[SI+18],CX      ;SUBTRACT CHARS-NOT-READ FROM CHARS-REQUESTED
  258.                                   ;(THIS RETURNS CHARS-ACTUALLY-READ)
  259.          JMP   DONE
  260. READ     ENDP
  261.  
  262. TESTREAD PROC  NEAR               ; 5 -- NON-DESTRUCTIVE INPUT NO WAIT
  263.          MOV   AX,7600H           ;AH = 76H (CHAR SOURCE TO AL); AL = 00H
  264.          INT   16H                ;IF BAT NOT INSTALLED, AL NOT CHANGED
  265.                                   ;IF BAT INSTALLED, AL = 'K'EYBOARD/'S'TACK
  266.          TEST  AL,AL              ;CHECK FOR UNCHANGED AL
  267.          JZ    UNKNOWN            ;IF BAT NOT INSTALLED, WE DON'T SUPPORT FUNCTION
  268.          CMP   AL,'S'             ;IF NO CHARS IN STACK
  269.          JE    TEST_READ_STACK
  270.          MOV   AL,EOF             ;RETURN EOF CHAR IN THAT CASE
  271.          JMP   SHORT TESTRET
  272. TEST_READ_STACK:                  ;STACK CHAR IS AVAILABLE
  273.          XOR   AH,AH              ;AH = 0: READ NEXT CHAR FROM STACK
  274.          INT   16H                ;GET CHAR INTO AL
  275.          MOV   AH,74H             ;PUT THAT CHAR BACK ON TOP OF STACK
  276.          INT   16H
  277. TESTRET:
  278.          MOV   DS:[SI+13],AL      ;SHOW CHAR TO CALLER
  279.          JMP   DONE
  280. TESTREAD ENDP
  281.          PAGE
  282. INSTATUS PROC  NEAR               ; 6 -- INPUT STATUS
  283.          JMP   DONE               ;NEVER SET 'BUSY' BIT
  284. INSTATUS ENDP
  285.  
  286. INFLUSH  PROC  NEAR               ; 7 -- INPUT FLUSH
  287.          MOV   AH,77H             ;PURGE THE STACK
  288.          INT   16H
  289.          JMP   DONE
  290. INFLUSH  ENDP
  291.  
  292. WRITE    PROC  NEAR               ;8, 9 -- OUTPUT (WRITE) [WITH VERIFY]
  293.          MOV   CX,DS:[SI+18]      ;PICK UP BYTE COUNT
  294.          JCXZ  DONE               ;IGNORE TRIVIAL REQUESTS
  295.          MOV   AX,7600H           ;REQUEST 'K' OR 'S' IN AL, CLEAR AL
  296.          INT   16H                ;AL UNCHANGED IF EBL NOT INSTALLED
  297.          TEST  AL,AL              ;CHECK FOR UNCHANGED AL
  298.          LJZ   UNKNOWN            ;USELESS TO WRITE TO BATSTACK WITHOUT EBL
  299.          PUSH  DS
  300.          PUSH  SI
  301.          LDS   SI,DS:[SI+14]      ;PICK UP TRANSFER ADDRESS
  302. WRITELOOP:
  303.          LODSB                    ;GET NEXT CHAR INTO AL
  304.          CMP   LASTWRITE,CR       ;WAS PREVIOUS CHARACTER CR?
  305.          MOV   LASTWRITE,AL       ;IN ANY CASE, UPDATE LAST-WRITTEN CHAR
  306.          JNE   WRITEOK            ;NOT CR, IN WHICH CASE ALLOW EXPLICIT LF
  307.          CMP   AL,LF              ;LINE FEED:  IGNORE THEM (CR/LF --> JUST CR)
  308.          JE    NOWRITE
  309. WRITEOK:
  310.          MOV   AH,73H             ;STACK AL'S CHAR FIFO STYLE
  311.          INT   16H                ;"WRITE" THE CHAR
  312. ;;       WE'D LIKE TO CHECK FOR SUCCESSFUL WRITE, BUT NO STATUS IS DOCUMENTED!
  313. NOWRITE:
  314.          LOOP  WRITELOOP          ;LOOP UNTIL ALL REQUESTED BYTES WRITTEN
  315.          POP   SI
  316.          POP   DS
  317.          SUB   DS:[SI+18],CX      ;SUBTRACT CHARS-NOT-WRITTEN FROM CHARS-REQUESTED
  318.                                   ;(THIS RETURNS CHARS-ACTUALLY-WRITTEN)
  319.          JMP   DONE
  320. WRITE    ENDP
  321.  
  322. TOP      EQU   THIS BYTE          ;TRUNCATE HERE AFTER INITIALIZATION
  323.          PAGE
  324. STARTMSG DB    0DH,0AH,'BATSTACK driver loaded',0DH,0AH,'$'
  325.  
  326. INIT     PROC  NEAR               ; 0 -- INIT
  327.          PUSH  DI
  328.          PUSH  ES
  329.          PUSH  AX
  330.          PUSH  BX
  331.          PUSH  CX
  332.          PUSH  DS                 ;SAVE AGAIN; WE CHANGE FOR DOS CALL
  333.          PUSH  SI
  334.          PUSH  DX
  335.          PUSH  BP
  336.          MOV   AX,CS              ;PTR TO CSEG
  337.          MOV   DS,AX              ;GET DS->CSEG
  338.          MOV   AH,9               ;DOS PRINT STRING
  339.          MOV   DX,OFFSET STARTMSG ;DS:DX -> MESSAGE
  340.          INT   21H                ;ASK DOS TO OUTPUT THE STRING
  341.          POP   BP
  342.          POP   DX
  343.          POP   SI
  344.          POP   DS                 ;RESTORE REQHDR SEG PTR
  345.          POP   CX
  346.          POP   BX
  347.          POP   AX
  348.          POP   ES
  349.          POP   DI
  350.          MOV   WORD PTR DS:[SI+16],CS  ;SEGMENT PART OF ENDING ADDRESS
  351.          MOV   WORD PTR DS:[SI+14],OFFSET TOP+MYSTACKSIZE ;OFFSET PART OF ENDING ADDR
  352.          MOV   MYSP,OFFSET TOP+MYSTACKSIZE  ;NEXT ENTRY, USE HIGH END AS STACK
  353.          JMP   DONE
  354. INIT     ENDP
  355.  
  356. CSEG     ENDS
  357.          END